﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.IO;

namespace RazorTemplateEngine
{
    public class AssemblyReferenceResolver
    {
        private Dictionary<string, Assembly> assemblyStore = new Dictionary<string, Assembly>();

        private Assembly _targetAssembly;

        public AssemblyReferenceResolver(Assembly targetAssembly)
        {
            _targetAssembly = targetAssembly;
        }

        public List<Assembly> RecurseReferenceAssemblies
        {
            get {
                assemblyStore.Clear();
                PushReferenceAssembly(_targetAssembly);
                return assemblyStore.Values.ToList();
            }
        }

        private void PushReferenceAssembly(Assembly parent)
        {
            if (parent == null) return;
            AssemblyName[] referenceAssembly = parent.GetReferencedAssemblies();
            if (referenceAssembly == null) return;
            foreach (AssemblyName an in referenceAssembly)
            {
                Assembly _assembly = TryLoadAssemblyByAssemblyName(an, assemblyStore);
                if (_assembly != null){
                    PushAssembly(_assembly);
                    PushReferenceAssembly(_assembly);
                }
            }
        }

        private Assembly TryLoadAssemblyByAssemblyName(AssemblyName assemblyName, Dictionary<string, Assembly> assemblyStore)
        {
            Assembly pAssemblyReferenced = null;
            try
            {
                pAssemblyReferenced = Assembly.Load(assemblyName);
            }
            catch
            { }
            if (pAssemblyReferenced == null)
            {
                try
                {
                    pAssemblyReferenced = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory
                        + assemblyName.Name + ".dll");
                }
                catch (Exception)
                {
                }
            }
            if (pAssemblyReferenced != null && assemblyStore.ContainsKey(pAssemblyReferenced.FullName)) return null;
            return pAssemblyReferenced;
        }

        private void PushAssembly(Assembly assembly)
        {
            if (assembly == null) return;
            if (assemblyStore.ContainsKey(assembly.FullName)) return;
            assemblyStore.Add(assembly.FullName, assembly);
        }
    }
}
